S3互換のCloudflare R2で署名付きURLを発行する(AWS CLI, Python + Boto3)
どうも、ベルリンオフィスの小西です。
S3 互換のオブジェクトストレージ Cloudflare R2 では、S3 同様に署名付き URL をサポートしており、今回はそちらを試してみたいと思います。
先に書いておくと、作業は S3 に対して行うのとほぼ一緒です。S3互換ってそういうことかという感じで読んでもらえれば。
R2 署名付き URL でできること
署名付き URL を作成することで、バケット全体やオブジェクトを完全公開することなく、URL と署名を知る一部のユーザーのみに対し、期限付きでバケットやオブジェクトのアクセス・操作許可を付与することができます。
例えば、
- 一部のユーザーに、1 時間のみ限定のオブジェクトダウンロード URL を配布する
- 一部の管理者に、24h 有効なオブジェクトアップロード URL を配布する
R2 バケットの準備
R2バケットの作成方法については以前に下記で紹介していますので、そちら参考にしていただければと思います。
作成したバケットはプライベートのままにしておいてください。
ダウンロード用の署名付き URL を発行する by AWS CLI
R2 操作には下記の AWS SDK がそのまま利用できます。
- AWS SDK for Go
- AWS SDK for JS v3
- AWS SDK for JS
- AWS SDK for PHP
- AWS CLI
- Cloudflare ページには記載がなかったですが、後述の通り Python SDKである boto でも署名付きURLを発行できました。
今回は AWS CLI で R2 バケットの署名付き URL を発行してみたいと思います。
1. R2 の API トークンの生成
以前の記事でも紹介していますが、トークン作成は下記の流れになります。
- Cloudflare ダッシュボードで R2 に移動する
- ダッシュボード右側 [Manage R2 API Tokens] に移動
- [Create API token] をクリックする
- [Token name] を編集する
- [Permissions] で [Edit] 選択する
- [Create API Token] をクリックする
2. AWS CLI の準備
AWS の CLI を使いますので、まだの人はこちらを参考にダウンロードしてください。
AWS アクセスの設定を行います。キー情報は先ほど Cloudflare R2 側で生成したトークンを入力します。
$ aws configure aws configureAWS Access Key ID : <ACCESS_KEY_ID> AWS Secret Access Key : <ACCESS_KEY_SECRET> Default region name : auto Default output format : json
3. 署名付き URL の作成
CLI では、オブジェクトダウンロード用 URL 発行は下記のコマンドになります。
$ aws s3 presign --endpoint-url https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com s3://<R2_BUCKETT_NAME>/<R2_OBJECT_PATH> --expires-in 3600
例えば下記の例は、対象オブジェクトに対し 3 分(= 180秒)の有効期限付きURLが発行できます。
$ aws s3 presign --endpoint-url https://142411ba14a3fd8e6dce641de1152c07.r2.cloudflarestorage.com s3://sample/sample.pdf --expires-in 180
上記を実行すると、署名パラメータが付与されたURLが返ってきます。
https://142411ba14a3fd8e6dce641de1152c07.r2.cloudflarestorage.com/sample/sample.pdf?X-Amz-Algorithm...
3分後にアクセスすると想定通り、期限切れのエラー(403)が返ってきます。
<Error> <Code>ExpiredRequest</Code> <Message>Request has expired</Message> </Error>
ここで発行する “署名” は、指定したオブジェクトと指定したアクションに限定されます。
試しにアクセス先のオブジェクトパスのみ変更し、それ以外のパラメータは同様の URL にアクセスすると、403 の SignatureDoesNotMatch
というエラーコードが返され、オブジェクトは閲覧できません。
<Error> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your secret access key and signing method. </Message> </Error>
有効期限について
署名付き URL には有効期限の設定が必要です。
タイムアウト期間は 1 秒から 7 日(= 604,800秒)の間で設定可能です。
署名付き URL のパラメーターとして、URLの生成時刻(例: X-Amz-Date=20230104T130633Z
)とタイムアウト(例: X-Amz-Expires=180
)が含まれ、これらを改ざんしても同様に SignatureDoesNotMatch
の 403 が返ります。
独自ドメインの利用
R2 ではバケットに対して独自ドメインを充てることができます。
署名付き URL の発行時に独自ドメインを指定したところ、URL自体は発行されましたが、アクセスすると 404 エラーが返ってきました。
利用は Cloudflare R2 の URL でのみ利用できる点も注意が必要です。
アップロード用の署名付き URL を発行する by Python + Boto3
AWS CLI ではアップロード用の署名付き URL は発行できません(知らなかった)。
せっかくなので Python + boto3 を使ってアップロード用の署名付き URL を発行してみます。
Python に boto3 のインストール
$ pip install boto3
Pythonのコード
まず試しに下記を実行し、R2 のバケット一覧が返ってきたら成功です。
import boto3 r2 = boto3.resource('s3', endpoint_url = 'https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com', aws_access_key_id = '<ACCESS_KEY_ID>', aws_secret_access_key = '<ACCESS_KEY_SECRET>' ) for bucket in r2.buckets.all(): print(bucket)
次に署名付き URL を実際に生成するコードです。
import boto3 BUCKET = 'test-konishi' KEY = 'sample' #任意のオブジェクトキー s3 = boto3.client('s3', endpoint_url = 'https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com', aws_access_key_id = '<ACCESS_KEY_ID>', aws_secret_access_key = '<ACCESS_KEY_SECRET>' ) response = s3.generate_presigned_url( ClientMethod = 'put_object', Params = {'Bucket' : BUCKET, 'Key' : KEY}, ExpiresIn = 300, HttpMethod = 'PUT') print(response)
上記を実行すると URL が返ってきます。
https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com/<R2_BUCKETT_NAME>/<R2_OBJECT_PATH>?X-Amz-Algorithm...
上記に対してオブジェクトを投稿してみます。
$ echo This is a sample. > sample.txt $ export URL="<先ほど発行されたURL>" $ curl -D - -X PUT --upload-file sample.txt $URL
成功すると下記のような返り値になります。 Server
が AmazonS3
ではなく cloudflare
になってますね。
HTTP/1.1 100 Continue HTTP/1.1 200 OK Date: Wed, 04 Jan 2023 14:41:04 GMT Content-Type: text/plain;charset=UTF-8 Content-Length: 0 Connection: keep-alive ETag: "9b9af6945c95f1aa302a61acf75c9bd6" x-amz-version-id: 56c671e83d23484da97eca5b325571d2 Server: cloudflare CF-RAY: 7844bba4dd4f2c45-FRA
Cloudflare R2 のダッシュボードに行くと、無事オブジェクトが PUT されていました。
以上、やりかたは S3 のそれと一緒でした。
Python + Boto3 で署名付き URL を生成する詳しい方法については、下記記事で紹介しています。
そのほかの留意点
- Public になったバケットのオブジェクト URL は Cloudflare アカウント ID とバケット名を含まない一方、署名付き URL はバケット保有者の アカウント ID とバケット名を含むようになり、それらが公になる点に留意が必要です。(とはいえこれらが漏れたところで、通常の運用範囲内であれば直接的な影響はないかと思います)
最後に
以上、特にダウンロード URL の生成は非常に簡単に行えることが見ていただけたかと思います。また同様の制限を Workers で実装する例もドキュメントで紹介されています。
クラスメソッドは Cloudflare のパートナーになっています。ご興味のある方、お困りの方は是非一度クラスメソッドにご相談ください。